Logging
CellularJS provide a lightweight package for logging called @cellularjs/logger
. The main purpose of this package is providing a unify logger interface that decouple your code from underlying logger implementation.
The way it work is similar to SLF4J. Logger interface is not subject to change, but you can easily create a new logger implementation that suit your needs(Eg: OTEL, write log to file,...).
Installation:
yarn add @cellularjs/logger
Or
npm install @cellularjs/logger
#
1. Logger#
1.1. getLoggerYou can use getLogger
function to get new logger instance. The new logger instance MUST inherit log level
, metadata
from its parent.
import { getLogger, LogLevel } from '@cellularjs/logger';
const logger = getLogger('UserProfile', { trace: '****' });logger.setLogLevel(LogLevel.DEBUG);
logger.debug('debug message');logger.info('info message');logger.warn('warn message');logger.error('error message', { error: 'stack trace', trace: '****#**' });logger.fatal('fatal message', { trace: '****#***' });
Output(default format):
2022-11-02T15:49:16.188Z DEBUG - UserProfile: debug message{ trace: '****' }2022-11-02T15:49:16.188Z INFO - UserProfile: info message{ trace: '****' }2022-11-02T15:49:16.188Z WARN - UserProfile: warn message{ trace: '****' }2022-11-02T15:49:16.188Z ERROR - UserProfile: error message{ error: 'stack trace', trace: '****#**' }2022-11-02T15:49:16.188Z FATAL - UserProfile: fatal message{ trace: '****#***' }
#
1.2. LogLevelCellularJS Logger support 5 levels of severity, the lower value the higher severity.
Level | Value | Recommended content |
---|---|---|
LogLevel.FATAL | 0 | Critical issue, something important is not working(Eg: failed to connect to database). |
LogLevel.ERROR | 1 | Error, but it is not critical to take an immediate action. |
LogLevel.WARN | 2 | Something unusual happened(Eg: API limit request exceed,..). |
LogLevel.INFO | 3 | Normal event occur(Eg: incoming request,...). |
LogLevel.DEBUG | 4 | Detail information for debugging(Eg: SQL query, operation steps,...). |
note
By default, the log level of root logger is LogLevel.INFO
, so if new logger is created from the root logger, it will inherit this log level. You can change the log level at runtime by using childLogger.setLogLevel
.
import { getLogger, LogLevel } from '@cellularjs/logger';
const logger = getLogger('UserProfile');
logger.debug('debug message'); // ignored(because default log level is LogLevel.INFO)logger.info('info message'); // work
// With log level, you can filter what should be logged or ignored.logger.setLogLevel(LogLevel.ERROR);
logger.debug('debug message'); // ignoredlogger.info('info message'); // ignoredlogger.warn('warn message'); // ignoredlogger.error('error message'); // worklogger.fatal('fatal message'); // work
#
2. Custom loggerThe default logger is very simple. For advanced usage, you can plug-in other logger such as winston, pino,...
Eg: use winston as underlying logger.
import { createLogger } from 'winston';import { setLoggerFactory, LoggerFactory, Logger, LogMessage, LogMeta } from '@cellularjs/logger';
const winston = createLogger({ level: 'debug', // ...});
class WinstonLogger implements Logger { // It is not a MUST, but for seamless developer experience, // you SHOULD use LogLevel.INFO as default log level. private logLevel = LogLevel.INFO;
constructor(private source?: string, private meta: LogMeta = {}) {}
from(source: string, meta?: LogMeta): Logger { const newLogger = new WinstonLogger(source, { ...this.meta, ...meta });
newLogger.setLogLevel(this.level);
return newLogger; }
info(msg: LogMessage, meta?: LogMeta) { if (this.logLevel < LogLevel.INFO) return;
winston.info(msg.toString(), { ...this.meta, ...meta }); }
... other stuff ...}
class WinstonLoggerFactory implements LoggerFactory { private rootLogger = new WinstonLogger();
getLogger(source: string, meta: LogMeta) { const activeLogger: Logger = this.rootLogger;
return activeLogger.from(source || activeLogger.getSource(), meta); }}
// register WinstonLoggerFactory as logger factorysetLoggerFactory(new WinstonLoggerFactory());
// now you can get your new logger support by winston.const myLogger = getLogger();
myLogger.info('...');
tip
For example about logger implementation, have a look at CellularJS simple logger